#include "common.h"
#include "server.h"
#include "Decryptor.h"

#ifdef DEBUG
#define KEYFILE		"localkeys/creditco.pem"
#else
#define KEYFILE		"realkeys/creditco.pem"
#endif

#define PASSWORD	"password"

void handle_connection(SSL *ssl, int s);
bool CheckPI(struct PaymentInfo* pi);

Decryptor* myDecryptor = NULL;

//we're just going to check for cardnum, lastname, and exp.
//in case user enters a shorted name or middle name abbreviation
struct cardHolderInfo {
	const char ch_last_name[PI_CH_LAST_NAME_LEN + 1];
	const char card_num[PI_CARD_NUM_LEN + 1];
	const char exp_date[PI_EXP_DATE_LEN + 1];
};
#define NUM_CARDHOLDERS 3
struct cardHolderInfo cardHolderArray[NUM_CARDHOLDERS] =
{
  {"fujinoki",  "1234567812345678", "0911"},
  {"chelmecki", "2356362345345527", "1012"},
  {"henry",     "7987234590345122", "0113"},
};

int main(int argc, char **argv) {
	SSLServer* server = new SSLServer(KEYFILE, PASSWORD, CREDITCO_SERVER_PORT,
			handle_connection);

	myDecryptor = new Decryptor(CREDITCO_PRIV_KEY);
	server->WaitForConnection();
	exit(0);
}

void handle_connection(SSL *ssl, int s) {
	int decrypted_size;
	unsigned char* buf;
	struct PaymentInfo* decryptedData;
	uint32_t enc_pkt_size;

	printf("new connection\r\n");

	// get size of entire EVP packet
	SSL_read_until_full(ssl, &enc_pkt_size, sizeof(uint32_t));
	enc_pkt_size = ntohl(enc_pkt_size);
	buf = new unsigned char[enc_pkt_size];

	// read and decrypt EVP packet
	SSL_read_until_full(ssl, buf, enc_pkt_size);

#ifndef NOENCRYPT
	decryptedData = (struct PaymentInfo*) (void*) myDecryptor->DecryptPacket(
			buf, enc_pkt_size, &decrypted_size);
	delete[] buf;

  // verify digests ----
	unsigned int pi_digest_len = 0;
	unsigned char* pi_str = prep_for_digest(*decryptedData);
	unsigned char* pi_digest = sha1_digest(pi_str, strlen((char*) pi_str) + 1, &pi_digest_len);

	int diff = strncmp((const char*) pi_digest, (const char*) decryptedData->message_digest, pi_digest_len);
	if (diff != 0) {
		printf("Error: inconsistent PI digests.\n");
		return;
	}

	delete[] pi_str;
	delete[] pi_digest;

#else
	decryptedData = (struct PaymentInfo*)(void*)buf;
	decrypted_size = enc_pkt_size;
#endif

	// printf("Charge Information:\n %s\n", decryptedData->card_num);

	delete decryptedData;

	if (CheckPI(decryptedData))
		SSL_write(ssl, ACK_STRING, sizeof(ACK_STRING));
	else
		SSL_write(ssl, NACK_STRING, sizeof(NACK_STRING));

}

bool CheckPI(struct PaymentInfo* pi)
{
  //this obviously isn't implemented to handle more than a small number of cardholders

	int cardIndex;
	int numCards = NUM_CARDHOLDERS;

	//find cardnumber
	for (cardIndex = 0; cardIndex < numCards; cardIndex++) {
		if ((memcmp(cardHolderArray[cardIndex].card_num, pi->card_num,
				PI_CARD_NUM_LEN) == 0) && (memcmp(
				cardHolderArray[cardIndex].ch_last_name, pi->ch_last_name,
				PI_CH_LAST_NAME_LEN) == 0) && (memcmp(
				cardHolderArray[cardIndex].exp_date, pi->exp_date,
				PI_EXP_DATE_LEN) == 0)) {
			return (true);
		}

	}

	return (false);
}
